﻿using System;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Security;
using System.Web;
using System.Xml;
using System.Xml.Serialization;

namespace Portal.Api
{
  /// <summary>
  /// A class that contains Basic functionality for a module.
  /// </summary>
  public class ModuleDocument
  {
    /// <summary>
    /// Constructor.
    /// </summary>
    /// <param name="moduleRef">The unique Module reference from the Portal Definition</param>
    /// <param name="moduleType">The module Type as string</param>
    public ModuleDocument(string moduleRef, string moduleType)
    {
      _moduleRef = moduleRef;
      _dataVirtualPath = Config.GetModuleDataVirtualPath(moduleType);
      _moduleType = moduleType;
      _templateSourceDirectory = Config.GetModulePhysicalPath(moduleType);
    }

    /// <summary>
    /// The unique Module reference from the Portal Definition. Readonly.
    /// </summary>
    public string ModuleRef { get { return _moduleRef; } }
    private string _moduleRef;

    /// <summary>
    /// The module Type as string. Readonly.
    /// </summary>
    public string ModuleType { get { return _moduleType; } }
    private string _moduleType;

    /// <summary>
    /// Modules virtual base path. Readonly.
    /// </summary>
    public string DataVirtualPath { get { return _dataVirtualPath; } }
    private string _dataVirtualPath;

    /// <summary>
    /// The relative path of the the module source directory.
    /// </summary>
    private string _templateSourceDirectory;

    /// <summary>
    /// Modules physical base path for the data. Readonly
    /// </summary>
    public string DataPhysicalPath
    {
      get
      {
        try
        {
          String ModPhysPath = HttpContext.Current.Server.MapPath(_dataVirtualPath);
          if (!ModPhysPath.EndsWith("\\", StringComparison.OrdinalIgnoreCase))    // XP Home does not include a trailing backslash.
            ModPhysPath += "\\";

          // Make sure the directory exists.
          if (!System.IO.Directory.Exists(ModPhysPath))
            System.IO.Directory.CreateDirectory(ModPhysPath);

          return ModPhysPath;
        }
        catch (ArgumentNullException)
        {
          return "";
        }
      }
    }

    /// <summary>
    /// The path to the Module Configurationfile.
    /// </summary>
    public string ModuleConfigFile 
    {
      get
      {
        return Path.Combine(DataPhysicalPath,  "Module_" + ModuleRef + ".config");
      }
    }

    /// <summary>
    /// The path to the Module Configuration Schema File.
    /// </summary>
    public string ModuleConfigSchemaFile
    {
      get
      {
        return Path.Combine(_templateSourceDirectory, "Module.xsd");
      }
    }


    /// <summary>
    /// Reads the common configuration of this moduletype.
    /// </summary>
    /// <param name="type">The type of the configuration.</param>
    /// <returns>The configuration or null, if an error occured</returns>
    public object ReadCommonConfig(System.Type type)
    {
      string fileName = Path.Combine(DataPhysicalPath, "Module.config");

      if (!System.IO.File.Exists(fileName))
        return null;

      XmlTextReader xmlReader = null;
      XmlSerializer xmlSerial = new XmlSerializer(type);
      object o = null;
      Exception e = null;
      try
      {
        xmlReader = new XmlTextReader(fileName);
        o = xmlSerial.Deserialize(xmlReader);
        xmlReader.Close();
        return o;
      }
      catch (FileNotFoundException ex) { e = ex; }
      catch (DirectoryNotFoundException ex) { e = ex; }
      catch (UriFormatException ex) { e = ex; }
      catch (WebException ex) { e = ex; }
      catch (InvalidOperationException ex) { e = ex; }
      finally
      {
        if (xmlReader != null)
        {
          xmlReader.Close();
        }
        // Do not throw exceptions
        Trace.TraceWarning("Module", Language.GetText("ErrorLoadingModulesCommonConfig"), e);
      }

      return o;
    }


    /// <summary>
    /// Reads the config file. The schema is optional.
    /// </summary>
    /// <returns>
    /// Null if config file does not exists and no schema exists,
    /// else the schema is read and a empty DataSet is returned.
    /// </returns>
    public DataSet ReadConfig()
    {
      DataSet ds = null;
      try
      {
        if (System.IO.File.Exists(ModuleConfigFile))
        {
          ds = new DataSet();
          string modCfgSchema = ModuleConfigSchemaFile;
          if (System.IO.File.Exists(modCfgSchema))
          {
            ds.ReadXmlSchema(modCfgSchema);
          }
          ds.ReadXml(ModuleConfigFile);
        }
      }
      catch (SecurityException e)
      {
        // Do not throw exceptions
        Trace.TraceWarning("Module", Language.GetText("ErrorLoadingModulesConfigDataset"), e);
        return null;
      }

      if (ds == null && System.IO.File.Exists(ModuleConfigSchemaFile))
      {
        ds = new DataSet();
        ds.ReadXmlSchema(ModuleConfigSchemaFile);
      }

      return ds;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public object ReadConfig(System.Type type)
    {
      return ReadConfig(type, ModuleConfigFile);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="type"></param>
    /// <param name="fileName"></param>
    /// <returns></returns>
    public static object ReadConfig(System.Type type, string fileName)
    {
      if (!System.IO.File.Exists(fileName))
        return null;

      XmlTextReader xmlReader = null;
      XmlSerializer xmlSerial = new XmlSerializer(type);
      object o = null;
      Exception e = null;
      try
      {
        xmlReader = new XmlTextReader(fileName);
        o = xmlSerial.Deserialize(xmlReader);
        xmlReader.Close();
      }
      catch (FileNotFoundException ex) { e = ex; }
      catch (DirectoryNotFoundException ex) { e = ex; }
      catch (UriFormatException ex) { e = ex; }
      catch (WebException ex) { e = ex; }
      catch (InvalidOperationException ex) { e = ex; }
      finally
      {
        if (xmlReader != null)
        {
          xmlReader.Close();
        }
        // Do not throw exceptions
        Trace.TraceWarning("Module", Language.GetText("ErrorLoadingModulesConfig"), e);
      }

      return o;
    }

    public void WriteConfig(DataSet ds)
    {
      if (null == ds)
        throw new ArgumentException(Language.GetText("exception_NullReferenceParameter"), "ds");
      try
      {
        ds.WriteXml(ModuleConfigFile);
      }
      catch (SecurityException e)
      {
        // Do not throw exceptions
        Trace.TraceWarning("Module", Language.GetText("ErrorWritingModulesConfigDataset"), e);
      }
    }

    public void WriteConfig(object obj)
    {
      WriteConfig(obj, ModuleConfigFile);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="o"></param>
    /// <param name="fileName"></param>
    public static void WriteConfig(object obj, string fileName)
    {
      if (null == obj)
        return;

      XmlTextWriter xmlWriter = null;
      XmlSerializer xmlSerial = new XmlSerializer(obj.GetType());
      Exception e = null;
      try
      {
        // Make sure the directory exists.
        System.IO.FileInfo fileInfo = new FileInfo(fileName);
        if (!fileInfo.Directory.Exists)
          System.IO.Directory.CreateDirectory(fileInfo.Directory.FullName);

        xmlWriter = new XmlTextWriter(fileName, System.Text.Encoding.UTF8);
        xmlWriter.Formatting = Formatting.Indented;
        xmlSerial.Serialize(xmlWriter, obj);
        xmlWriter.Close();
      }
      catch (ArgumentNullException ex) { e = ex; }
      catch (ArgumentException ex) { e = ex; }
      catch (DirectoryNotFoundException ex) { e = ex; }
      catch (UnauthorizedAccessException ex) { e = ex; }
      catch (SecurityException ex) { e = ex; }
      catch (IOException ex) { e = ex; }
      finally
      {
        if (xmlWriter != null)
        {
          xmlWriter.Close();
        }
        // Do not throw exceptions
        Trace.TraceWarning("Module", Language.GetText("ErrorWritingModulesConfig"), e);
      }
    }

  }
}
